﻿using System;
using System.Threading.Tasks;

namespace Encloser.Toolkit
{
    public class Mission
    {
        private readonly Atomic<Func<bool>> task = new Atomic<Func<bool>>(null);
        private readonly AtomicInt threadNum = new AtomicInt();
        private readonly AtomicInt maxNum = new AtomicInt();
        private readonly Action stopCallback;

        public bool IsRunning { get => task.Value != null; }

        public Mission(Action stopCallback = null)
        {
            this.stopCallback = stopCallback;
        }

        public void Start(Func<bool> task, int maxThreadNum)
        {
            if (task == null || maxThreadNum < 1 || !this.task.CAS(null, task)) return;
            Adjust(maxThreadNum);
        }

        public void Adjust(int maxThreadNum)
        {
            if (maxThreadNum < 1 || !IsRunning) return;
            var num = (maxNum.Value = maxThreadNum) - threadNum.Value;
            for (var i = 0; i < num; i++)
            {
                new Task(() =>
                {
                    threadNum.Increase();
                    while (true)
                    {
                        if (threadNum.DecreaseIf(v => v > maxNum.Value)) return;
                        var t = task.Value;
                        if (t == null || t()) break;
                    }
                    if (threadNum.DecreaseAndGet() <= 0)
                    {
                        task.Value = null;
                        stopCallback?.Invoke();
                    }
                }).Start();
            }
        }

        public void Stop()
        {
            task.Value = null;
        }
    }
}
